/**
 * VYPe11 Project
 * VYPe11 language compiler.
 * Authors: Jozef Lang (xlangj01), 
 * 			Zoltan Zemko (xzemko01)
 * 2011
 */
package cz.vutbr.fit.VYPe.team18.VYPe11.codegeneration.MIPS32;

import java.util.*;

import cz.vutbr.fit.VYPe.team18.VYPe11.codegeneration.*;

/**
 * StackItem
 */
final class StackItem {
	public final int address;
	public final int size;
	
	public StackItem(final int addr, final int size) {
		this.address = addr;
		/**
		 * If size = -1, frame
		 */
		this.size = size;
	}
}

/**
 * MIPS32 DataStack implementation.
 * DataStack is implemented as Stack
 * MIPS32 DataStack runs from top to down.
 * The accepted are following:
 * - int - 32bit 
 * - short - 16bit
 * - char - 8bit
 * - String - a set of chars
 */
public final class MIPS32DataStack extends Stack<StackItem> implements IDataStack {
	
	/**
	 * Stack TOP address
	 */
	private int _topAddress;
	private final int _baseAddress;
	
	public MIPS32DataStack(final int baseAddress) {
		_baseAddress = baseAddress;
		_topAddress = _baseAddress;
	}
	
	public int getHeadAddress() {
		return _topAddress;
	}

	@Override
	public int pushInteger() {
		int storeAddress = _topAddress;
		this.push(new StackItem(_topAddress, MIPS32AssemblerGenerator.INTEGER_SIZE));
		_topAddress += MIPS32AssemblerGenerator.INTEGER_SIZE;
		return storeAddress;
	}

	@Override
	public int pushShort() {
		int storeAddress = _topAddress;
		this.push(new StackItem(_topAddress, MIPS32AssemblerGenerator.SHORT_SIZE));
		_topAddress += MIPS32AssemblerGenerator.SHORT_SIZE;
		return storeAddress;
	}

	@Override
	public int pushChar() {
		int storeAddress = _topAddress;
		this.push(new StackItem(_topAddress, MIPS32AssemblerGenerator.CHAR_SIZE));
		_topAddress += MIPS32AssemblerGenerator.CHAR_SIZE;
		return storeAddress;
	}

	@Override
	public int pushString(final int length) {
		int storeAddress = _topAddress;
		this.push(new StackItem(_topAddress, MIPS32AssemblerGenerator.CHAR_SIZE*(length + 1)));
		_topAddress += MIPS32AssemblerGenerator.CHAR_SIZE*(length + 1);
		return storeAddress;
	}

	@Override
	public int pushFrame() {
		int storeAddress = _topAddress;
		this.push(new StackItem(_topAddress, -1));
		_topAddress += 0;
		return storeAddress;
	}
	
	@Override
	public int popItem() {
		StackItem itm = super.pop();
		_topAddress = itm.address;
		return _topAddress;
	}

	@Override
	public int popToFrame() {
		// Pops to StackFrame or till stack is empty
		int retAddress = _topAddress;
		while (true) {
			try {
				StackItem itm = super.pop();
				if (itm.size == -1) {
					// Store frame address
					retAddress = itm.address;
				}
			} catch (EmptyStackException e) {
				// We are at the bottom of the stack
				retAddress = _baseAddress;
				break;
			}
		}
		// Move Stack address head
		_topAddress = retAddress;
		return retAddress;
	}

}